﻿using System.Threading;
using System.Threading.Tasks;
using ESRI.ArcGIS.Client.Geometry;

namespace ESRI.ArcGIS.Client.Tasks.Async
{
    public static partial class MensurationTaskExtensions
    {
        #region AreaAndPerimeterTaskAsync

        /// <summary>
        /// Asynchronous task that calculates the area on an image serviced based on a geometry surface.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The geometry surface area.</param>
        /// <param name="parameters">Parameters used in the calculation of the area.</param>
        /// <returns></returns>
        public static Task<MensurationAreaTaskResult> AreaAndPerimeterTaskAsync(this MensurationTask task,
            Envelope surfaceArea, MensurationAreaParameter parameters)
        {
            return AreaAndPerimeterTaskAsync(task, surfaceArea, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that calculates the area on an image serviced based on a geometry surface.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The geometry surface area.</param>
        /// <param name="parameters">Parameters used in the calculation of the area.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationAreaTaskResult> AreaAndPerimeterTaskAsync(this MensurationTask task,
            Envelope surfaceArea, MensurationAreaParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationAreaEventArgs, MensurationAreaTaskResult>(
                t => t.AreaAndPerimeterAsync(surfaceArea, parameters),
                (t, e) => t.AreaAndPerimeterCompleted += e,
                (t, e) => t.AreaAndPerimeterCompleted -= e,
                e => new MensurationAreaTaskResult(e),
                cancellationToken);
        }

        /// <summary>
        /// Asynchronous task that calculates the area on an image serviced based on a geometry surface.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The geometry surface area.</param>
        /// <param name="parameters">Parameters used in the calculation of the area.</param>
        /// <returns></returns>
        public static Task<MensurationAreaTaskResult> AreaAndPerimeterTaskAsync(this MensurationTask task,
            Polygon surfaceArea, MensurationAreaParameter parameters)
        {
            return AreaAndPerimeterTaskAsync(task, surfaceArea, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that calculates the area on an image serviced based on a geometry surface.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The geometry surface area.</param>
        /// <param name="parameters">Parameters used in the calculation of the area.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationAreaTaskResult> AreaAndPerimeterTaskAsync(this MensurationTask task,
            Polygon surfaceArea, MensurationAreaParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationAreaEventArgs, MensurationAreaTaskResult>(
                t => t.AreaAndPerimeterAsync(surfaceArea, parameters),
                (t, e) => t.AreaAndPerimeterCompleted += e,
                (t, e) => t.AreaAndPerimeterCompleted -= e,
                e => new MensurationAreaTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region CentroidTaskAsync

        /// <summary>
        /// Asynchronous task that evaluates a central location on a surface area located on an image serviced.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The surface area to evaluate.</param>
        /// <param name="parameters">Parameters used in the centroid evaluation.</param>
        /// <returns></returns>
        public static Task<MensurationPointTaskResult> CentroidTaskAsync(this MensurationTask task,
            Envelope surfaceArea, MensurationPointParameter parameters)
        {
            return CentroidTaskAsync(task, surfaceArea, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that evaluates a central location on a surface area located on an image serviced.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The surface area to evaluate.</param>
        /// <param name="parameters">Parameters used in the centroid evaluation.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationPointTaskResult> CentroidTaskAsync(this MensurationTask task,
            Envelope surfaceArea, MensurationPointParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationPointEventArgs, MensurationPointTaskResult>(
                t => t.CentroidAsync(surfaceArea, parameters),
                (t, e) => t.CentroidCompleted += e,
                (t, e) => t.CentroidCompleted -= e,
                e => new MensurationPointTaskResult(e),
                cancellationToken);
        }

        /// <summary>
        /// Asynchronous task that evaluates a central location on a surface area located on an image serviced.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The surface area to evaluate.</param>
        /// <param name="parameters">Parameters used in the centroid evaluation.</param>
        /// <returns></returns>
        public static Task<MensurationPointTaskResult> CentroidTaskAsync(this MensurationTask task,
            Polygon surfaceArea, MensurationPointParameter parameters)
        {
            return CentroidTaskAsync(task, surfaceArea, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that evaluates a central location on a surface area located on an image serviced.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="surfaceArea">The surface area to evaluate.</param>
        /// <param name="parameters">Parameters used in the centroid evaluation.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationPointTaskResult> CentroidTaskAsync(this MensurationTask task,
            Polygon surfaceArea, MensurationPointParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationPointEventArgs, MensurationPointTaskResult>(
                t => t.CentroidAsync(surfaceArea, parameters),
                (t, e) => t.CentroidCompleted += e,
                (t, e) => t.CentroidCompleted -= e,
                e => new MensurationPointTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region DistanceAndAngleTaskAsync

        /// <summary>
        /// Asynchronous task that calculates the distance and angle between to points on an image service.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="point1">The first point.</param>
        /// <param name="point2">The second point.</param>
        /// <param name="parameters">Parameters used in the calculation of the distance and angle of the two points.</param>
        /// <returns></returns>
        public static Task<MensurationLengthTaskResult> DistanceAndAngleTaskAsync(this MensurationTask task,
            MapPoint point1, MapPoint point2, MensurationLengthParameter parameters)
        {
            return DistanceAndAngleTaskAsync(task, point1, point2, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that calculates the distance and angle between to points on an image service.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="point1">The first point.</param>
        /// <param name="point2">The second point.</param>
        /// <param name="parameters">Parameters used in the calculation of the distance and angle of the two points.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationLengthTaskResult> DistanceAndAngleTaskAsync(this MensurationTask task,
            MapPoint point1, MapPoint point2, MensurationLengthParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationLengthEventArgs, MensurationLengthTaskResult>(
                t => t.DistanceAndAngleAsync(point1, point2, parameters),
                (t, e) => t.DistanceAndAngleCompleted += e,
                (t, e) => t.DistanceAndAngleCompleted -= e,
                e => new MensurationLengthTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region HeightFromBaseAndTopTaskAsync

        /// <summary>
        /// Asynchronous task that calculates the height of a structure from a point at the base to a point at the top of the structure.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="basePoint">The point located at the base of the structure.</param>
        /// <param name="topPoint">The point located at the top of the structure.</param>
        /// <param name="parameters">Parameters used in the calculation of the height of the structure.</param>
        /// <returns></returns>
        public static Task<MensurationHeightTaskResult> HeightFromBaseAndTopTaskAsync(this MensurationTask task,
            MapPoint basePoint, MapPoint topPoint, MensurationHeightParameter parameters)
        {
            return HeightFromBaseAndTopTaskAsync(task, basePoint, topPoint, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that calculates the height of a structure from a point at the base to a point at the top of the structure.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="basePoint">The point located at the base of the structure.</param>
        /// <param name="topPoint">The point located at the top of the structure.</param>
        /// <param name="parameters">Parameters used in the calculation of the height of the structure.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationHeightTaskResult> HeightFromBaseAndTopTaskAsync(this MensurationTask task,
            MapPoint basePoint, MapPoint topPoint, MensurationHeightParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationHeightEventArgs, MensurationHeightTaskResult>(
                t => t.HeightFromBaseAndTopAsync(basePoint, topPoint, parameters),
                (t, e) => t.HeightFromBaseAndTopCompleted += e,
                (t, e) => t.HeightFromBaseAndTopCompleted -= e,
                e => new MensurationHeightTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region HeightFromBaseAndTopShadowTaskAsync

        /// <summary>
        /// Asynchronous task that calculates the height of a structure from a point at the base to a point at the top of the structures shadow.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="basePoint">The point located at the base of the structure.</param>
        /// <param name="topShadowPoint">The point located at the top of the structures shadow.</param>
        /// <param name="parameters">Parameters used in the calculation of the height of the structure.</param>
        /// <returns></returns>
        public static Task<MensurationHeightTaskResult> HeightFromBaseAndTopShadowTaskAsync(this MensurationTask task,
            MapPoint basePoint, MapPoint topShadowPoint, MensurationHeightParameter parameters)
        {
            return HeightFromBaseAndTopShadowTaskAsync(task, basePoint, topShadowPoint, parameters,
                CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that calculates the height of a structure from a point at the base to a point at the top of the structures shadow.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="basePoint">The point located at the base of the structure.</param>
        /// <param name="topShadowPoint">The point located at the top of the structures shadow.</param>
        /// <param name="parameters">Parameters used in the calculation of the height of the structure.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationHeightTaskResult> HeightFromBaseAndTopShadowTaskAsync(this MensurationTask task,
            MapPoint basePoint, MapPoint topShadowPoint, MensurationHeightParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationHeightEventArgs, MensurationHeightTaskResult>(
                t => t.HeightFromBaseAndTopShadowAsync(basePoint, topShadowPoint, parameters),
                (t, e) => t.HeightFromBaseAndTopShadowCompleted += e,
                (t, e) => t.HeightFromBaseAndTopShadowCompleted -= e,
                e => new MensurationHeightTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region HeightFromTopAndTopShadowTaskAsync

        /// <summary>
        /// Asynchronous task that calculates the height of a structure from a point at the top of the structure to a point at the top of the structures shadow.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="topPoint">The point located at the top of the structure.</param>
        /// <param name="topShadowPoint">The point located at the top of the structures shadow.</param>
        /// <param name="parameters">Parameters used in the calculation of the height of the structure.</param>
        /// <returns></returns>
        public static Task<MensurationHeightTaskResult> HeightFromTopAndTopShadowTaskAsync(this MensurationTask task,
            MapPoint topPoint, MapPoint topShadowPoint, MensurationHeightParameter parameters)
        {
            return HeightFromTopAndTopShadowTaskAsync(task, topPoint, topShadowPoint, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that calculates the height of a structure from a point at the top of the structure to a point at the top of the structures shadow.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="topPoint">The point located at the top of the structure.</param>
        /// <param name="topShadowPoint">The point located at the top of the structures shadow.</param>
        /// <param name="parameters">Parameters used in the calculation of the height of the structure.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationHeightTaskResult> HeightFromTopAndTopShadowTaskAsync(this MensurationTask task,
            MapPoint topPoint, MapPoint topShadowPoint, MensurationHeightParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationHeightEventArgs, MensurationHeightTaskResult>(
                t => t.HeightFromTopAndTopShadowAsync(topPoint, topShadowPoint, parameters),
                (t, e) => t.HeightFromTopAndTopShadowCompleted += e,
                (t, e) => t.HeightFromTopAndTopShadowCompleted -= e,
                e => new MensurationHeightTaskResult(e),
                cancellationToken);
        }

        #endregion

        #region PointTaskAsync

        /// <summary>
        /// Asynchronous task that gets location information from an image service based on a geometry point.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="point">The point to evaluate on the image service.</param>
        /// <param name="parameters">Parameters used in the evaluation of the geometry point.</param>
        /// <returns></returns>
        public static Task<MensurationPointTaskResult> PointTaskAsync(this MensurationTask task,
            MapPoint point, MensurationPointParameter parameters)
        {
            return PointTaskAsync(task, point, parameters, CancellationToken.None);
        }

        /// <summary>
        /// Asynchronous task that gets location information from an image service based on a geometry point.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="point">The point to evaluate on the image service.</param>
        /// <param name="parameters">Parameters used in the evaluation of the geometry point.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<MensurationPointTaskResult> PointTaskAsync(this MensurationTask task,
            MapPoint point, MensurationPointParameter parameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<MensurationTask, MensurationPointEventArgs, MensurationPointTaskResult>(
                t => t.PointAsync(point, parameters),
                (t, e) => t.PointCompleted += e,
                (t, e) => t.PointCompleted -= e,
                e => new MensurationPointTaskResult(e),
                cancellationToken);
        }

        #endregion
    }
}


